
#include <iostream>
#include <parser.h>
#include <gtest/gtest.h>
#include <printer.h>
#include <vm.h>
#include <instruction.h>
#include <cgen.h>
#define TEST_FILE "./test_case.c"

size_t read_file(char *buf, size_t size, const char *filename) {
  FILE *fp = fopen(filename, "r");
  if (!fp) return 0;
  size_t rlen = fread(buf, 1, size, fp);
  fclose(fp);
  return rlen;
}

TEST(test, test_cgen) {
  char buf[1024];
  size_t rlen = read_file(buf, sizeof buf, TEST_FILE);

  ASSERT_GE(rlen, 0);

  Lexer lexer(buf, rlen);
  Parser parser(lexer);
  Stat block = parser.parse();
  Cgen p;
  generateStat(&p, block);
  std::vector<uint32_t> codes;
  for (auto& i : p.codes) {
    if (i._type == kLabel) {
      printf("%s:\n", i._label.c_str());
    } else {
      if (i._label.size())
        printf("%s | %s\n", dump(i.emit()).c_str(), i._label.c_str());
      else 
        printf("%s\n", dump(i.emit()).c_str());
    }
  }
}

TEST(test, test_printer) {
  char buf[1024];
  size_t rlen = read_file(buf, sizeof buf, TEST_FILE);

  ASSERT_GE(rlen, 0);

  Lexer lexer(buf, rlen);
  Parser parser(lexer);
  Stat block = parser.parse();
  Printer p;
  generateStat(&p, block);
  for (auto &s : p.content) std::cout << s;
}


TEST(test, test_typedef) {
    std::string raw = "typedef enum color Color;";
    Lexer lexer(&raw[0], raw.size());
    Parser parser(lexer);

    Stat block = parser.parse();

    ASSERT_EQ(stat, stat);
}


TEST(test, test_reassemble) {
  uint32_t code2[] = {
    0x27bdffd8,0xafbf0024,0xafbe0020,0x03a0f025,
    0x3c023b9a,0x3445ca00,0x24040069,0x0c1001c0,
    0x00000000,0xafc2001c,0x8fc2001c,0x3c036666,
    0x34636667,0x00430018,0x00001810,0x00031843,
    0x000217c3,0x00621023,0xafc2001c,0x00001025,
    0x03c0e825,0x8fbf0024,0x8fbe0020,0x27bd0028,
    0x03e00008,MIPS_EXIT
  };

  uint32_t code[] = {
      0x33bdffe0, 0xafdd001c, 0x03a0f025, 0x10000000, 0x10000000,
      0x10000000, 0x03c0e825, 0x8fbe001c, 0x33bd0020, 0x03e00008,
      MIPS_EXIT,
  };

  VM vm(code, sizeof code);
  auto stat = vm.dump();
}

int main(int argc, char *argv[]) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}


/*
 
  40076c:	27bdffd8 	addiu	sp,sp,-40
  400770:	afbf0024 	sw	ra,36(sp)
  400774:	afbe0020 	sw	s8,32(sp)
  400778:	03a0f025 	move	s8,sp
  40077c:	3c023b9a 	lui	v0,0x3b9a
  400780:	3445ca00 	ori	a1,v0,0xca00
  400784:	24040069 	li	a0,105
  400788:	0c1001c0 	jal	400700 <func_add>
  40078c:	00000000 	nop
  400790:	afc2001c 	sw	v0,28(s8)
  400794:	8fc2001c 	lw	v0,28(s8)
  400798:	3c036666 	lui	v1,0x6666
  40079c:	34636667 	ori	v1,v1,0x6667
  4007a0:	00430018 	mult	v0,v1
  4007a4:	00001810 	mfhi	v1
  4007a8:	00031843 	sra	v1,v1,0x1
  4007ac:	000217c3 	sra	v0,v0,0x1f
  4007b0:	00621023 	subu	v0,v1,v0
  4007b4:	afc2001c 	sw	v0,28(s8)
  4007b8:	00001025 	move	v0,zero
  4007bc:	03c0e825 	move	sp,s8
  4007c0:	8fbf0024 	lw	ra,36(sp)
  4007c4:	8fbe0020 	lw	s8,32(sp)
  4007c8:	27bd0028 	addiu	sp,sp,40
  4007cc:	03e00008 	jr	ra
 */

